package com.edfapp.costom;

import com.edfapp.utils.ListProcessor;
import com.edfapp.utils.TimeUtils;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;

/**
 * @author hong
 * @description 描述
 * @time 2025/9/18 18:38
 **/
public class DsEDFWriter {

    // EDF配置类，用于创建新的EDF文件
    public static class EDFConfig {
        public String version = "0";  // 标准EDF版本为0
        public String patientId = "";
        public String recordId = "";
        public String startDate = "01.01.00";  // 格式: dd.mm.yy
        public String startTime = "00.00.00";  // 格式: hh.mm.ss
        public String edfId = "EDF";  // 标准无事件EDF标识->EDF;注释信号通道(annotations-signal)时->EDF+C

        public float recordDuration = 1;  // 每条记录持续1秒
        public String[] signalLabels;
        public String[] transducerTypes;
        public String[] physicalDimensions;
        public float[] physicalMin;
        public float[] physicalMax;
        public int[] digitalMin = new int[]{-32768};  // 默认数字最小值
        public int[] digitalMax = new int[]{32767};   // 默认数字最大值
        public String[] prefiltering;
        public float[] samplingRates;  // 采样率(Hz)
    }
    /**
     * 根据EDF配置和信号数据生成EDF文件
     * @param config EDF配置信息
     * @param signalData 信号数据列表，每个double[]对应一个通道的数据
     * @param outputFile 输出的EDF文件
     * @throws IOException 如果文件写入失败
     */
    public void generateEDFFile(EDFConfig config, List<Double[]> signalData, File outputFile) throws IOException {
        if (config == null || signalData == null) {
            throw new IllegalArgumentException("配置和信号数据不能为空");
        }

        if (config.signalLabels == null || config.signalLabels.length != signalData.size()) {
            throw new IllegalArgumentException("信号标签数量与信号数据数量不匹配");
        }

        try (RandomAccessFile raf = new RandomAccessFile(outputFile, "rw")) {
            // 1. 计算必要的参数
            int numberOfSignals = signalData.size();

            // 计算每条记录的样本数（基于采样率和记录持续时间）
            int[] samplesPerRecord = new int[numberOfSignals];
            for (int i = 0; i < numberOfSignals; i++) {
                samplesPerRecord[i] = (int) (config.samplingRates[i] * config.recordDuration);
            }

            // 计算数据记录数量（基于第一个信号的数据长度）
            int numberOfRecords = signalData.get(0).length / samplesPerRecord[0];

            // 2. 写入文件头
            writeHeader(raf, config, numberOfSignals, numberOfRecords, samplesPerRecord);

            // 3. 写入信号数据
            writeSignalData(raf, config, signalData, numberOfSignals, numberOfRecords, samplesPerRecord);
        }
    }

    /**
     * 写入EDF文件头
     */
    private void writeHeader(RandomAccessFile raf, EDFConfig config,
                             int numberOfSignals, int numberOfRecords, int[] samplesPerRecord) throws IOException {
        // 版本信息 (8字节)
        writeFixedString(raf, config.version != null ? config.version : "0", 8);

        // 用户标识 (80字节)
        writeFixedString(raf, config.patientId != null ? config.patientId : "X X X X", 80);

        // 记录标识 (80字节)
        writeFixedString(raf, config.recordId != null ? config.recordId : "Startdate X X X", 80);

        // 开始日期 (8字节)
        writeFixedString(raf, config.startDate != null ? config.startDate : "01.01.00", 8);

        // 开始时间 (8字节)
        writeFixedString(raf, config.startTime != null ? config.startTime : "00.00.00", 8);

        // 头信息长度 (8字节) - 先写占位符，后面再更新
        long headerSizePosition = raf.getFilePointer();
        writeFixedString(raf, "0", 8);

        // EDF标识 (44字节)
        writeFixedString(raf, config.edfId != null ? config.edfId : "EDF+C", 44);

        // 数据记录数量 (8字节)
        writeFixedString(raf, String.valueOf(numberOfRecords), 8);

        // 每条记录的持续时间(秒) (8字节)
        writeFixedString(raf, String.valueOf(config.recordDuration), 8);

        // 信号数量 (4字节)
        writeFixedString(raf, String.valueOf(numberOfSignals), 4);

        // 信号标签 (每个16字节)
        for (int i = 0; i < numberOfSignals; i++) {
            writeFixedString(raf, config.signalLabels[i], 16);
        }

        // 传感器类型 (每个80字节)
        for (int i = 0; i < numberOfSignals; i++) {
            String transducerType = config.transducerTypes != null && i < config.transducerTypes.length ?
                    config.transducerTypes[i] : "";
            writeFixedString(raf, transducerType, 80);
        }

        // 物理维度 (每个8字节)
        for (int i = 0; i < numberOfSignals; i++) {
            String physicalDim = config.physicalDimensions != null && i < config.physicalDimensions.length ?
                    config.physicalDimensions[i] : "uV";
            writeFixedString(raf, physicalDim, 8);
        }

        // 物理最小值 (每个8字节)
        for (int i = 0; i < numberOfSignals; i++) {
            float physMin = config.physicalMin != null && i < config.physicalMin.length ?
                    config.physicalMin[i] : -1000.0f;
            writeFixedString(raf, String.valueOf(physMin), 8);
        }

        // 物理最大值 (每个8字节)
        for (int i = 0; i < numberOfSignals; i++) {
            float physMax = config.physicalMax != null && i < config.physicalMax.length ?
                    config.physicalMax[i] : 1000.0f;
            writeFixedString(raf, String.valueOf(physMax), 8);
        }

        // 数字最小值 (每个8字节)
        for (int i = 0; i < numberOfSignals; i++) {
            int digitalMin = config.digitalMin != null && i < config.digitalMin.length ?
                    config.digitalMin[i] : -32768;
            writeFixedString(raf, String.valueOf(digitalMin), 8);
        }

        // 数字最大值 (每个8字节)
        for (int i = 0; i < numberOfSignals; i++) {
            int digitalMax = config.digitalMax != null && i < config.digitalMax.length ?
                    config.digitalMax[i] : 32767;
            writeFixedString(raf, String.valueOf(digitalMax), 8);
        }

        // 预滤波 (每个80字节)
        for (int i = 0; i < numberOfSignals; i++) {
            String prefilter = config.prefiltering != null && i < config.prefiltering.length ?
                    config.prefiltering[i] : "";
            writeFixedString(raf, prefilter, 80);
        }

        // 每条记录的样本数 (每个8字节)
        for (int i = 0; i < numberOfSignals; i++) {
            writeFixedString(raf, String.valueOf(samplesPerRecord[i]), 8);
        }

        // 保留字段 (每个32字节)
        for (int i = 0; i < numberOfSignals; i++) {
            writeFixedString(raf, "", 32);
        }

        // 更新头信息长度
        long currentPosition = raf.getFilePointer();
        raf.seek(headerSizePosition);
        writeFixedString(raf, String.valueOf(currentPosition), 8);
        raf.seek(currentPosition);
    }

    /**
     * 写入信号数据
     */
    private void writeSignalData(RandomAccessFile raf, EDFConfig config, List<Double[]> signalData,
                                 int numberOfSignals, int numberOfRecords, int[] samplesPerRecord) throws IOException {

        for (int r = 0; r < numberOfRecords; r++) {
            for (int s = 0; s < numberOfSignals; s++) {
                int samples = samplesPerRecord[s];
                Double[] signal = signalData.get(s);
                int startIndex = r * samples;

                // 计算转换因子
                float physRange = config.physicalMax[s] - config.physicalMin[s];
                int digitalRange = config.digitalMax[s] - config.digitalMin[s];
                float factor = digitalRange / physRange;

                // 写入样本数据
                for (int i = 0; i < samples; i++) {
                    if (startIndex + i >= signal.length) {
                        // 数据不足，填充0
                        raf.writeShort(0);
                        continue;
                    }

                    double physicalValue = signal[startIndex + i];

                    // 转换为数字值
                    short digitalValue = (short) (config.digitalMin[s] +
                            (physicalValue - config.physicalMin[s]) * factor);

                    raf.writeShort(digitalValue);
                }
            }
        }
    }

    /**
     * 写入固定长度的字符串
     */
    private void writeFixedString(RandomAccessFile raf, String str, int length) throws IOException {
        byte[] bytes = str.getBytes(StandardCharsets.ISO_8859_1);
        byte[] buffer = new byte[length];

        // 复制字符串内容
        int copyLength = Math.min(bytes.length, length);
        System.arraycopy(bytes, 0, buffer, 0, copyLength);

        // 剩余部分填充空格
        for (int i = copyLength; i < length; i++) {
            buffer[i] = ' ';
        }

        raf.write(buffer);
    }

    /**
     * 使用示例：生成EDF文件
     */
    public static void generateExampleEDF() {
        try {
            List<TXTBrainWave> txtBrainWaves = ListProcessor.text2List("C:\\Users\\xinho\\Desktop\\OnePlus-PHB110-Android-15_2025-09-28_121045.logcat");
            LocalDateTime today = LocalDateTime.now();
            DsEDFWriter parser = new DsEDFWriter();
            EDFParser parser1 = new EDFParser();
            // 创建配置
            EDFConfig config = new EDFConfig();
            config.patientId = "JYCX Li M 05-NOV-1990";
            config.recordId = "JYCX "+ TimeUtils.getRecordDate(today) + " TGAM";
            config.startDate = TimeUtils.getStartDate(today);
            config.startTime = TimeUtils.getStartTime(txtBrainWaves.get(0).getCollectTime());
            float hz = 1.0f; //512 Hz

            // 设置信号信息
            int numberOfChannels = 10;
            config.signalLabels = new String[]{"EEG att", "EEG med", "EEG delta", "EEG theta", "EEG lowAlpha","EEG highAlpha", "EEG lowBeta", "EEG highBeta","EEG lowGamma", "EEG middleGamma"};
            config.transducerTypes = new String[]{"AgAgCl electrode", "AgAgCl electrode", "AgAgCl electrode", "AgAgCl electrode", "AgAgCl electrode", "AgAgCl electrode", "AgAgCl electrode", "AgAgCl electrode", "AgAgCl electrode", "AgAgCl electrode"};
            config.physicalDimensions = new String[]{"uV", "uV", "uV", "uV", "uV", "uV", "uV", "uV", "uV", "uV"};
            config.physicalMin = new float[]{-32767.0f, -32767.0f, -32767.0f, -32767.0f, -32767.0f, -32767.0f, -32767.0f, -32767.0f, -32767.0f, -32767.0f};
            config.physicalMax = new float[]{32767.0f, 32767.0f, 32767.0f, 32767.0f, 32767.0f, 32767.0f, 32767.0f, 32767.0f, 32767.0f, 32767.0f};
            config.digitalMin = new int[]{-32768, -32768,-32768, -32768, -32768, -32768, -32768, -32768, -32768, -32768};
            config.digitalMax = new int[]{32767, 32767,32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767};
            config.prefiltering = new String[]{"HP:0.5Hz LP:100Hz","HP:0.5Hz LP:100Hz","HP:0.5Hz LP:5Hz", "HP:4Hz LP:8Hz", "HP:8Hz LP:10Hz", "HP:10Hz LP:13Hz", "HP:14Hz LP:30Hz", "HP:14Hz LP:30Hz", "HP:30Hz LP:50Hz", "HP:50Hz LP:70Hz"};
            config.samplingRates = new float[]{hz, hz, hz, hz, hz, hz, hz, hz, hz, hz}; // 512 Hz

            // 生成测试信号数据
            List<Double[]> testSignals = new ArrayList<>();
            for (int i = 0; i < numberOfChannels; i++) {
                if (i == 0){
                    Double[] signal = txtBrainWaves.stream().map(TXTBrainWave::getAtt).toArray(Double[]::new);
                    testSignals.add(signal);
                }else if (i == 1){
                    Double[] signal = txtBrainWaves.stream().map(TXTBrainWave::getMed).toArray(Double[]::new);
                    testSignals.add(signal);
                }else if (i == 2){
                    Double[] signal = txtBrainWaves.stream().map(TXTBrainWave::getDelta).toArray(Double[]::new);
                    testSignals.add(signal);
                }else if (i == 3){
                    Double[] signal = txtBrainWaves.stream().map(TXTBrainWave::getTheta).toArray(Double[]::new);
                    testSignals.add(signal);
                }else if (i == 4){
                    Double[] signal = txtBrainWaves.stream().map(TXTBrainWave::getLowAlpha).toArray(Double[]::new);
                    testSignals.add(signal);
                }else if (i == 5){
                    Double[] signal = txtBrainWaves.stream().map(TXTBrainWave::getHighAlpha).toArray(Double[]::new);
                    testSignals.add(signal);
                }else if (i == 6){
                    Double[] signal = txtBrainWaves.stream().map(TXTBrainWave::getLowBeta).toArray(Double[]::new);
                    testSignals.add(signal);
                }else if (i == 7){
                    Double[] signal = txtBrainWaves.stream().map(TXTBrainWave::getHighBeta).toArray(Double[]::new);
                    testSignals.add(signal);
                }else if (i == 8){
                    Double[] signal = txtBrainWaves.stream().map(TXTBrainWave::getLowGamma).toArray(Double[]::new);
                    testSignals.add(signal);
                }else {
                    Double[] signal = txtBrainWaves.stream().map(TXTBrainWave::getMiddleGamma).toArray(Double[]::new);
                    testSignals.add(signal);
                }

            }

            // 生成EDF文件
            File outputFile = new File("C:\\Users\\xinho\\Desktop\\"+TimeUtils.getFileName(today)+".edf");
            parser.generateEDFFile(config, testSignals, outputFile);

            System.out.println("EDF文件生成成功: " + outputFile.getAbsolutePath());

            // 验证生成的文件
            parser1.parse(outputFile);
            System.out.println("验证解析结果:");
            System.out.println(parser1.getHeader());

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
//        generateExampleEDF();
        System.setProperty("file.encoding", "UTF-8");
        System.out.println("你好");
    }
}
